package cn.enjoy.tool.juc.SimpleThreadPool;

import lombok.Data;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 简易线程池
 * 要点
 * workers=运行中的线程 jobs=任务列表
 * 1. 线程池内参数设置（核心线程数、最大线程数、正在运行的线程数workerNum、任务列表jobs、运行的线程列表、线程计数器threadNum）
 * 2. Worker（Runnable接口）
 *    running开关volatile
 *    对待执行任务列表（jobs）加锁，获取一个任务后解锁；没获取到任务等待，直到获取到任务
 * 3. jobs的操作都必须加锁
 *
 * @author K
 * @date 2021/7/30 下午3:23
 */
@Data
public class DefaultThreadPool<Job extends Runnable> implements ThreadPool<Job> {

    private int corePoolSize = 1;
    private int maxPoolSize = 10;
    private final LinkedList<Job> jobs = new LinkedList<>();
    private final List<Worker> workers = Collections.synchronizedList(new ArrayList<Worker>());
    private String threadNamePrefix;
    private AtomicInteger threadNum = new AtomicInteger();
    private int workerNum = corePoolSize;


    public DefaultThreadPool(int poolSize, String threadNamePrefix) {
        this.workerNum = poolSize;
        if (poolSize > maxPoolSize) {
            this.workerNum = maxPoolSize;
        }
        if (poolSize < corePoolSize) {
            this.workerNum = corePoolSize;
        }
        this.threadNamePrefix = threadNamePrefix;

        initializeWorkers(workerNum);
    }

    private void initializeWorkers(int poolSize) {
        for (int i = 0; i < poolSize; i++) {
            Worker worker = new Worker();
            workers.add(worker);
            Thread thread = new Thread(worker, threadNamePrefix + "--" + threadNum.getAndIncrement());
            thread.start();
        }
    }

    @Override
    public void execute(Job job) {
        if (job != null) {
            synchronized (jobs) {
                jobs.addLast(job);
                jobs.notify();
            }
        }
    }

    @Override
    public void shutdown() {
        for (Worker worker : workers) {
            worker.shutdown();
        }
    }

    @Override
    public void addWorkers(int num) {
        synchronized (jobs) {
            if (workerNum + num > maxPoolSize) {
                num = maxPoolSize - workerNum;
            }
            initializeWorkers(num);
            workerNum += num;
        }
    }

    @Override
    public void removeWorker(int num) {
        synchronized (jobs) {
            if (num >= workerNum) {
                throw new IllegalArgumentException("超出工作线程数");
            }
            int count = 0;
            for (int i = 0; i < num; i++) {
                Worker worker = workers.get(i);
                if (workers.remove(worker)) {
                    worker.shutdown();
                    count++;
                }
            }
            workerNum -= count;
        }
    }

    @Override
    public int getJobSize() {
        return jobs.size();
    }

    class Worker implements Runnable {
        private volatile boolean running = true;

        @Override
        public void run() {
            while (running) {
                Job job = null;
                // 对jobs生产者
                synchronized (jobs) {
                    while (jobs.isEmpty()) {
                        try {
                            jobs.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            return;
                        }
                    }
                    job = jobs.removeFirst();
                }

                if (job != null) {
                    try {
                        job.run();
                    } catch (Exception e) {
                    }
                }

            }
        }

        public void shutdown() {
            running = false;
        }
    }

}
